home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
- * ALL RIGHTS RESERVED
- * Permission to use, copy, modify, and distribute this software for
- * any purpose and without fee is hereby granted, provided that the above
- * copyright notice appear in all copies and that both the copyright notice
- * and this permission notice appear in supporting documentation, and that
- * the name of Silicon Graphics, Inc. not be used in advertising
- * or publicity pertaining to distribution of the software without specific,
- * written prior permission.
- *
- * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
- * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
- * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
- * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
- * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
- * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
- * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
- * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
- * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
- * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * US Government Users Restricted Rights
- * Use, duplication, or disclosure by the Government is subject to
- * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
- * (c)(1)(ii) of the Rights in Technical Data and Computer Software
- * clause at DFARS 252.227-7013 and/or in similar or successor
- * clauses in the FAR or the DOD or NASA FAR Supplement.
- * Unpublished-- rights reserved under the copyright laws of the
- * United States. Contractor/manufacturer is Silicon Graphics,
- * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
- *
- * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <malloc.h>
- #include <time.h>
- #include <math.h>
- #include "tk.h"
- #include "trackball.h"
-
- #define WIDTH 4
- #define HEIGHT 5
- #define PIECES 10
- #define OFFSETX -2
- #define OFFSETY -2.5
- #define OFFSETZ -0.5
-
- typedef char Config[HEIGHT][WIDTH];
-
- struct puzzle {
- struct puzzle *backptr;
- struct puzzle *solnptr;
- Config pieces;
- struct puzzle *next;
- unsigned hashvalue;
- };
-
- #define HASHSIZE 10691
-
- struct puzzlelist {
- struct puzzle *puzzle;
- struct puzzlelist *next;
- };
-
- static char convert[PIECES+1] = {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4};
-
- static unsigned char colors[PIECES+1][3] = {
- { 0, 0, 0},
- {255,255,127},
- {255,255,127},
- {255,255,127},
- {255,255,127},
- {255,127,255},
- {255,127,255},
- {255,127,255},
- {255,127,255},
- {255,127,127},
- {255,255,255},
- };
-
- static struct puzzle *hashtable[HASHSIZE];
- static struct puzzle *startPuzzle;
- static struct puzzlelist *puzzles;
- static struct puzzlelist *lastentry;
-
- #define MOVE_SPEED 0.2
- static unsigned char movingPiece;
- static float move_x,move_y;
- static float curquat[4];
- static int doubleBuffer=1;
- static int depth=1;
-
- static char xsize[PIECES+1] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
- static char ysize[PIECES+1] = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2 };
- static float zsize[PIECES+1] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.6 };
- static GLuint listbase;
-
- static Config startConfig = {
- { 8, 10, 10, 7 },
- { 8, 10, 10, 7 },
- { 6, 9, 9, 5 },
- { 6, 4, 3, 5 },
- { 2, 0, 0, 1 }
- };
-
- static Config thePuzzle = {
- { 8, 10, 10, 7 },
- { 8, 10, 10, 7 },
- { 6, 9, 9, 5 },
- { 6, 4, 3, 5 },
- { 2, 0, 0, 1 }
- };
-
- static int xadds[4]={-1, 0, 1, 0};
- static int yadds[4]={ 0,-1, 0, 1};
-
- static long W = 400, H = 300;
- static GLint viewport[4];
-
- #define srandom srand
- #define random() (rand() >> 2)
-
- unsigned hash(Config config)
- {
- int i,j,value;
-
- value=0;
- for (i=0; i<HEIGHT; i++) {
- for (j=0; j<WIDTH; j++) {
- value=value+convert[config[i][j]];
- value*=6;
- }
- }
- return(value);
- }
-
- int solution(Config config)
- {
- if (config[4][1]==10 && config[4][2]==10) return(1);
- return(0);
- }
-
- float boxcoords[][3] = {
- { 0.2, 0.2, 0.9 },
- { 0.8, 0.2, 0.9 },
- { 0.8, 0.8, 0.9 },
- { 0.2, 0.8, 0.9 },
- { 0.2, 0.1, 0.8 },
- { 0.8, 0.1, 0.8 },
- { 0.9, 0.2, 0.8 },
- { 0.9, 0.8, 0.8 },
- { 0.8, 0.9, 0.8 },
- { 0.2, 0.9, 0.8 },
- { 0.1, 0.8, 0.8 },
- { 0.1, 0.2, 0.8 },
- { 0.2, 0.1, 0.2 },
- { 0.8, 0.1, 0.2 },
- { 0.9, 0.2, 0.2 },
- { 0.9, 0.8, 0.2 },
- { 0.8, 0.9, 0.2 },
- { 0.2, 0.9, 0.2 },
- { 0.1, 0.8, 0.2 },
- { 0.1, 0.2, 0.2 },
- { 0.2, 0.2, 0.1 },
- { 0.8, 0.2, 0.1 },
- { 0.8, 0.8, 0.1 },
- { 0.2, 0.8, 0.1 },
- };
-
- float boxnormals[][3] = {
- { 0, 0, 1 }, /* 0 */
- { 0, 1, 0 },
- { 1, 0, 0 },
- { 0, 0,-1 },
- { 0,-1, 0 },
- {-1, 0, 0 },
- { 0.7071, 0.7071, 0.0000}, /* 6 */
- { 0.7071,-0.7071, 0.0000},
- {-0.7071, 0.7071, 0.0000},
- {-0.7071,-0.7071, 0.0000},
- { 0.7071, 0.0000, 0.7071}, /* 10 */
- { 0.7071, 0.0000,-0.7071},
- {-0.7071, 0.0000, 0.7071},
- {-0.7071, 0.0000,-0.7071},
- { 0.0000, 0.7071, 0.7071}, /* 14 */
- { 0.0000, 0.7071,-0.7071},
- { 0.0000,-0.7071, 0.7071},
- { 0.0000,-0.7071,-0.7071},
- { 0.5774, 0.5774, 0.5774}, /* 18 */
- { 0.5774, 0.5774,-0.5774},
- { 0.5774,-0.5774, 0.5774},
- { 0.5774,-0.5774,-0.5774},
- {-0.5774, 0.5774, 0.5774},
- {-0.5774, 0.5774,-0.5774},
- {-0.5774,-0.5774, 0.5774},
- {-0.5774,-0.5774,-0.5774},
- };
-
- int boxfaces[][4] = {
- { 0, 1, 2, 3 }, /* 0 */
- { 9, 8, 16, 17 },
- { 6, 14, 15, 7 },
- { 20, 23, 22, 21 },
- { 12, 13, 5, 4 },
- { 19, 11, 10, 18 },
- { 7, 15, 16, 8 }, /* 6 */
- { 13, 14, 6, 5 },
- { 18, 10, 9, 17 },
- { 19, 12, 4, 11 },
- { 1, 6, 7, 2 }, /* 10 */
- { 14, 21, 22, 15 },
- { 11, 0, 3, 10 },
- { 20, 19, 18, 23 },
- { 3, 2, 8, 9 }, /* 14 */
- { 17, 16, 22, 23 },
- { 4, 5, 1, 0 },
- { 20, 21, 13, 12 },
- { 2, 7, 8, -1 }, /* 18 */
- { 16, 15, 22, -1 },
- { 5, 6, 1, -1 },
- { 13, 21, 14, -1 },
- { 10, 3, 9, -1 },
- { 18, 17, 23, -1 },
- { 11, 4, 0, -1 },
- { 20, 12, 19, -1 },
- };
-
- #define NBOXFACES (sizeof(boxfaces)/sizeof(boxfaces[0]))
-
- /* Draw a box. Bevel as desired. */
- void drawBox(int piece, float xoff, float yoff)
- {
- int xlen, ylen;
- int i,j,k;
- float x,y,z;
- float zlen;
- float *v;
-
- xlen=xsize[piece];
- ylen=ysize[piece];
- zlen=zsize[piece];
-
- glColor3ubv(colors[piece]);
- glBegin(GL_QUADS);
- for (i=0; i<18; i++) {
- glNormal3fv(boxnormals[i]);
- for (k=0; k<4; k++) {
- if (boxfaces[i][k] == -1) continue;
- v=boxcoords[boxfaces[i][k]];
- x=v[0] + OFFSETX;
- if (v[0] > 0.5) x += xlen-1;
- y=v[1] + OFFSETY;
- if (v[1] > 0.5) y += ylen-1;
- z=v[2] + OFFSETZ;
- if (v[2] > 0.5) z += zlen-1;
- glVertex3f(xoff+x,yoff+y,z);
- }
- }
- glEnd();
- glBegin(GL_TRIANGLES);
- for (i=18; i<NBOXFACES; i++) {
- glNormal3fv(boxnormals[i]);
- for (k=0; k<3; k++) {
- if (boxfaces[i][k] == -1) continue;
- v=boxcoords[boxfaces[i][k]];
- x=v[0] + OFFSETX;
- if (v[0] > 0.5) x += xlen-1;
- y=v[1] + OFFSETY;
- if (v[1] > 0.5) y += ylen-1;
- z=v[2] + OFFSETZ;
- if (v[2] > 0.5) z += zlen-1;
- glVertex3f(xoff+x,yoff+y,z);
- }
- }
- glEnd();
- }
-
- float containercoords[][3] = {
- { -0.1, -0.1, 1.0 },
- { -0.1, -0.1, -0.1 },
- { 4.1, -0.1, -0.1 },
- { 4.1, -0.1, 1.0 },
- { 1.0, -0.1, 0.6 }, /* 4 */
- { 3.0, -0.1, 0.6 },
- { 1.0, -0.1, 0.0 },
- { 3.0, -0.1, 0.0 },
- { 1.0, 0.0, 0.0 }, /* 8 */
- { 3.0, 0.0, 0.0 },
- { 3.0, 0.0, 0.6 },
- { 1.0, 0.0, 0.6 },
- { 0.0, 0.0, 1.0 }, /* 12 */
- { 4.0, 0.0, 1.0 },
- { 4.0, 0.0, 0.0 },
- { 0.0, 0.0, 0.0 },
- { 0.0, 5.0, 0.0 }, /* 16 */
- { 0.0, 5.0, 1.0 },
- { 4.0, 5.0, 1.0 },
- { 4.0, 5.0, 0.0 },
- { -0.1, 5.1, -0.1 }, /* 20 */
- { 4.1, 5.1, -0.1 },
- { 4.1, 5.1, 1.0 },
- { -0.1, 5.1, 1.0 },
- };
-
- float containernormals[][3] = {
- { 0,-1, 0 },
- { 0,-1, 0 },
- { 0,-1, 0 },
- { 0,-1, 0 },
- { 0,-1, 0 },
- { 0, 1, 0 },
- { 0, 1, 0 },
- { 0, 1, 0 },
- { 1, 0, 0 },
- { 1, 0, 0 },
- { 1, 0, 0 },
- {-1, 0, 0 },
- {-1, 0, 0 },
- {-1, 0, 0 },
- { 0, 1, 0 },
- { 0, 0,-1 },
- { 0, 0,-1 },
- { 0, 0, 1 },
- { 0, 0, 1 },
- { 0, 0, 1 },
- { 0, 0, 1 },
- { 0, 0, 1 },
- { 0, 0, 1 },
- { 0, 0, 1 },
- };
-
- int containerfaces[][4] = {
- { 1, 6, 4, 0 },
- { 0, 4, 5, 3 },
- { 1, 2, 7, 6 },
- { 7, 2, 3, 5 },
- { 16, 19, 18, 17 },
-
- { 23, 22, 21, 20 },
- { 12, 11, 8, 15 },
- { 10, 13, 14, 9 },
-
- { 15, 16, 17, 12 },
- { 2, 21, 22, 3 },
- { 6, 8, 11, 4 },
-
- { 1, 0, 23, 20 },
- { 14, 13, 18, 19 },
- { 9, 7, 5, 10 },
-
- { 12, 13, 10, 11 },
-
- { 1, 20, 21, 2 },
- { 4, 11, 10, 5 },
-
- { 15, 8, 19, 16 },
- { 19, 8, 9, 14 },
- { 8, 6, 7, 9 },
- { 0, 3, 13, 12 },
- { 13, 3, 22, 18 },
- { 18, 22, 23, 17 },
- { 17, 23, 0, 12 },
- };
-
- #define NCONTFACES (sizeof(containerfaces)/sizeof(containerfaces[0]))
-
- /* Draw the container */
- void drawContainer(void)
- {
- int i,k;
- float *v;
-
- /* Y is reversed here because the model has it reversed */
-
- /* Arbitrary bright wood-like color */
- glColor3ub(209, 103, 23);
- glBegin(GL_QUADS);
- for (i=0; i<NCONTFACES; i++) {
- v=containernormals[i];
- glNormal3f(v[0], -v[1], v[2]);
- for (k=3; k>=0; k--) {
- v=containercoords[containerfaces[i][k]];
- glVertex3f(v[0]+OFFSETX, -(v[1]+OFFSETY), v[2]+OFFSETZ);
- }
- }
- glEnd();
- }
-
- void drawAll(int withTags)
- {
- int i,j;
- int piece;
- char done[PIECES+1];
- float m[4][4];
-
- build_rotmatrix(m, curquat);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- gluLookAt(0,0,10, 0,0,0, 0,-1,0);
- glMultMatrixf(&(m[0][0]));
-
- if (depth) {
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- } else {
- glClear(GL_COLOR_BUFFER_BIT);
- }
- for (i=1; i <= PIECES; i++) {
- done[i] = 0;
- }
- glLoadName(0);
- drawContainer();
- for (i=0; i<HEIGHT; i++) {
- for (j=0; j<WIDTH; j++) {
- piece = thePuzzle[i][j];
- if (piece == 0) continue;
- if (done[piece]) continue;
- done[piece] = 1;
- glLoadName(piece);
- if (piece == movingPiece) {
- drawBox(piece, move_x, move_y);
- } else {
- drawBox(piece, j, i);
- }
- }
- }
- }
-
- void redraw(void)
- {
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(45, 1.0, 0.1, 100.0);
-
- drawAll(GL_FALSE);
-
- if (doubleBuffer) tkSwapBuffers();
- }
-
- void solidifyChain(struct puzzle *puzzle)
- {
- int i;
-
- i=0;
- while (puzzle->backptr) {
- i++;
- puzzle->backptr->solnptr = puzzle;
- puzzle=puzzle->backptr;
- }
- printf("%d moves to complete!\n", i);
- }
-
- int addConfig(Config config, struct puzzle *back)
- {
- unsigned hashvalue;
- struct puzzle *newpiece;
- struct puzzlelist *newlistentry;
-
- hashvalue=hash(config);
-
- newpiece=hashtable[hashvalue % HASHSIZE];
- while (newpiece != NULL) {
- if (newpiece->hashvalue == hashvalue) {
- int i,j;
-
- for (i=0; i<WIDTH; i++) {
- for (j=0; j<HEIGHT; j++) {
- if (convert[config[j][i]] !=
- convert[newpiece->pieces[j][i]]) goto nomatch;
- }
- }
- return 0;
- }
- nomatch:
- newpiece=newpiece->next;
- }
-
- newpiece=(struct puzzle *) malloc(sizeof(struct puzzle));
- newpiece->next=hashtable[hashvalue % HASHSIZE];
- newpiece->hashvalue=hashvalue;
- memcpy(newpiece->pieces, config, HEIGHT*WIDTH);
- newpiece->backptr=back;
- newpiece->solnptr=NULL;
- hashtable[hashvalue % HASHSIZE]=newpiece;
-
- newlistentry=(struct puzzlelist *) malloc(sizeof(struct puzzlelist));
- newlistentry->puzzle=newpiece;
- newlistentry->next=NULL;
-
- if (lastentry) {
- lastentry->next=newlistentry;
- } else {
- puzzles=newlistentry;
- }
- lastentry=newlistentry;
-
- if (back == NULL) {
- startPuzzle = newpiece;
- }
-
- if (solution(config)) {
- solidifyChain(newpiece);
- return 1;
- }
-
- return 0;
- }
-
- /* Checks if a space can move */
- int canmove0(Config pieces, int x, int y, int dir, Config newpieces)
- {
- char piece;
- int xadd, yadd;
- int l,m;
-
- xadd=xadds[dir];
- yadd=yadds[dir];
-
- if (x+xadd<0 || x+xadd>=WIDTH ||
- y+yadd<0 || y+yadd>=HEIGHT) return 0;
- piece=pieces[y+yadd][x+xadd];
- if (piece==0) return 0;
- memcpy(newpieces, pieces, HEIGHT*WIDTH);
- for (l=0; l<WIDTH; l++) {
- for (m=0; m<HEIGHT; m++) {
- if (newpieces[m][l]==piece)
- newpieces[m][l]=0;
- }
- }
- xadd= -xadd;
- yadd= -yadd;
- for (l=0; l<WIDTH; l++) {
- for (m=0; m<HEIGHT; m++) {
- if (pieces[m][l]==piece) {
- int newx, newy;
-
- newx=l+xadd;
- newy=m+yadd;
- if (newx<0 || newx>=WIDTH ||
- newy<0 || newy>=HEIGHT) return 0;
- if (newpieces[newy][newx] != 0) return 0;
- newpieces[newy][newx]=piece;
- }
- }
- }
- return 1;
- }
-
- /* Checks if a piece can move */
- int canmove(Config pieces, int x, int y, int dir, Config newpieces)
- {
- int xadd, yadd;
-
- xadd=xadds[dir];
- yadd=yadds[dir];
-
- if (x+xadd<0 || x+xadd>=WIDTH ||
- y+yadd<0 || y+yadd>=HEIGHT) return 0;
- if (pieces[y+yadd][x+xadd] == pieces[y][x]) {
- return canmove(pieces, x+xadd, y+yadd, dir, newpieces);
- }
- if (pieces[y+yadd][x+xadd] != 0) return 0;
- return canmove0(pieces, x+xadd, y+yadd, (dir+2) % 4, newpieces);
- }
-
- int generateNewConfigs(struct puzzle *puzzle)
- {
- int i,j,k;
- Config pieces;
- Config newpieces;
-
- memcpy(pieces, puzzle->pieces, HEIGHT*WIDTH);
- for (i=0; i<WIDTH; i++) {
- for (j=0; j<HEIGHT; j++) {
- if (pieces[j][i] == 0) {
- for (k=0; k<4; k++) {
- if (canmove0(pieces, i, j, k, newpieces)) {
- if (addConfig(newpieces, puzzle)) return 1;
- }
- }
- }
- }
- }
- return 0;
- }
-
- void freeSolutions(void)
- {
- struct puzzlelist *nextpuz;
- struct puzzle *puzzle, *next;
- int i;
-
- while (puzzles) {
- nextpuz = puzzles->next;
- free((char *) puzzles);
- puzzles=nextpuz;
- }
- lastentry = NULL;
- for (i=0; i<HASHSIZE; i++) {
- puzzle = hashtable[i];
- hashtable[i] = NULL;
- while (puzzle) {
- next = puzzle->next;
- free((char *) puzzle);
- puzzle = next;
- }
- }
- startPuzzle = NULL;
- }
-
- int continueSolving(void)
- {
- struct puzzle *nextpuz;
- int i,j;
- int movedPiece;
- int movedir;
- int fromx, fromy;
- int tox, toy;
-
- if (startPuzzle == NULL) return 0;
- if (startPuzzle->solnptr == NULL) {
- freeSolutions();
- return 0;
- }
-
- nextpuz = startPuzzle->solnptr;
- movedPiece=0;
- movedir=0;
- for (i=0; i<HEIGHT; i++) {
- for (j=0; j<WIDTH; j++) {
- if (startPuzzle->pieces[i][j] != nextpuz->pieces[i][j]) {
- if (startPuzzle->pieces[i][j]) {
- movedPiece=startPuzzle->pieces[i][j];
- fromx=j;
- fromy=i;
- if (i<HEIGHT-1 && nextpuz->pieces[i+1][j] == movedPiece) {
- movedir=3;
- } else {
- movedir=2;
- }
- goto found_piece;
- } else {
- movedPiece=nextpuz->pieces[i][j];
- if (i<HEIGHT-1 &&
- startPuzzle->pieces[i+1][j] == movedPiece) {
- fromx=j;
- fromy=i+1;
- movedir=1;
- } else {
- fromx=j+1;
- fromy=i;
- movedir=0;
- }
- goto found_piece;
- }
- }
- }
- }
- printf("What! No change?\n");
- freeSolutions();
- return 0;
-
- found_piece:
- if (!movingPiece) {
- movingPiece = movedPiece;
- move_x = fromx;
- move_y = fromy;
- }
- move_x += xadds[movedir] * MOVE_SPEED;
- move_y += yadds[movedir] * MOVE_SPEED;
-
- tox = fromx + xadds[movedir];
- toy = fromy + yadds[movedir];
-
- if (move_x > tox - MOVE_SPEED/2 && move_x < tox + MOVE_SPEED/2 &&
- move_y > toy - MOVE_SPEED/2 && move_y < toy + MOVE_SPEED/2) {
- startPuzzle = nextpuz;
- movingPiece=0;
- }
-
- memcpy(thePuzzle, startPuzzle->pieces, HEIGHT*WIDTH);
- return 1;
- }
-
- int solvePuzzle(void)
- {
- struct puzzlelist *nextpuz;
- int i;
-
- if (solution(thePuzzle)) {
- printf("Puzzle already solved!\n");
- return 0;
- }
- addConfig(thePuzzle, NULL);
- i=0;
-
- while (puzzles) {
- i++;
- if (generateNewConfigs(puzzles->puzzle)) break;
- nextpuz=puzzles->next;
- free((char *) puzzles);
- puzzles=nextpuz;
- }
- if (puzzles == NULL) {
- freeSolutions();
- printf("I can't solve it! (%d positions examined)\n", i);
- return 1;
- }
- return 1;
- }
-
- int selectPiece(int mousex, int mousey)
- {
- long hits;
- GLuint selectBuf[1024];
- GLuint closest;
- GLuint dist;
-
- glSelectBuffer(1024, selectBuf);
- (void) glRenderMode(GL_SELECT);
- glInitNames();
-
- /* Because LoadName() won't work with no names on the stack */
- glPushName(-1);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPickMatrix(mousex, H-mousey, 4, 4, viewport);
- gluPerspective(45, 1.0, 0.1, 100.0);
-
- drawAll(GL_TRUE);
-
- hits = glRenderMode(GL_RENDER);
- if (hits <= 0) {
- return 0;
- }
-
- closest=0;
- dist=4294967295;
- while (hits) {
- if (selectBuf[(hits-1)*4+1] < dist) {
- dist = selectBuf[(hits-1)*4+1];
- closest = selectBuf[(hits-1)*4+3];
- }
- hits--;
- }
- return closest;
- }
-
- void nukePiece(int piece)
- {
- int i,j;
-
- for (i=0; i<HEIGHT; i++) {
- for (j=0; j<WIDTH; j++) {
- if (thePuzzle[i][j] == piece) {
- thePuzzle[i][j] = 0;
- }
- }
- }
- }
-
- void multMatrices(const GLfloat a[16], const GLfloat b[16], GLfloat r[16])
- {
- int i, j;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- r[i*4+j] =
- a[i*4+0]*b[0*4+j] +
- a[i*4+1]*b[1*4+j] +
- a[i*4+2]*b[2*4+j] +
- a[i*4+3]*b[3*4+j];
- }
- }
- }
-
- void makeIdentity(GLfloat m[16])
- {
- m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
- m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
- m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
- m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
- }
-
- /*
- ** inverse = invert(src)
- */
- int invertMatrix(const GLfloat src[16], GLfloat inverse[16])
- {
- int i, j, k, swap;
- double t;
- GLfloat temp[4][4];
-
- for (i=0; i<4; i++) {
- for (j=0; j<4; j++) {
- temp[i][j] = src[i*4+j];
- }
- }
- makeIdentity(inverse);
-
- for (i = 0; i < 4; i++) {
- /*
- ** Look for largest element in column
- */
- swap = i;
- for (j = i + 1; j < 4; j++) {
- if (fabs(temp[j][i]) > fabs(temp[i][i])) {
- swap = j;
- }
- }
-
- if (swap != i) {
- /*
- ** Swap rows.
- */
- for (k = 0; k < 4; k++) {
- t = temp[i][k];
- temp[i][k] = temp[swap][k];
- temp[swap][k] = t;
-
- t = inverse[i*4+k];
- inverse[i*4+k] = inverse[swap*4+k];
- inverse[swap*4+k] = t;
- }
- }
-
- if (temp[i][i] == 0) {
- /*
- ** No non-zero pivot. The matrix is singular, which shouldn't
- ** happen. This means the user gave us a bad matrix.
- */
- return 0;
- }
-
- t = temp[i][i];
- for (k = 0; k < 4; k++) {
- temp[i][k] /= t;
- inverse[i*4+k] /= t;
- }
- for (j = 0; j < 4; j++) {
- if (j != i) {
- t = temp[j][i];
- for (k = 0; k < 4; k++) {
- temp[j][k] -= temp[i][k]*t;
- inverse[j*4+k] -= inverse[i*4+k]*t;
- }
- }
- }
- }
- return 1;
- }
-
- /*
- ** This is a screwball function. What it does is the following:
- ** Given screen x and y coordinates, compute the corresponding object space
- ** x and y coordinates given that the object space z is 0.9 + OFFSETZ.
- ** Since the tops of (most) pieces are at z = 0.9 + OFFSETZ, we use that
- ** number.
- */
- int computeCoords(int piece, int mousex, int mousey,
- GLfloat *selx, GLfloat *sely)
- {
- GLfloat modelMatrix[16];
- GLfloat projMatrix[16];
- GLfloat finalMatrix[16];
- GLfloat in[4];
- GLfloat a,b,c,d;
- GLfloat top, bot;
- GLfloat z;
- GLfloat w;
- GLfloat height;
-
- if (piece == 0) return 0;
- height = zsize[piece] - 0.1 + OFFSETZ;
-
- glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
- glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);
- multMatrices(modelMatrix, projMatrix, finalMatrix);
- if (!invertMatrix(finalMatrix, finalMatrix)) return 0;
-
- in[0] = (2.0 * (mousex - viewport[0]) / viewport[2]) - 1;
- in[1] = (2.0 * ((H - mousey) - viewport[1]) / viewport[3]) - 1;
-
- a = in[0] * finalMatrix[0*4+2] +
- in[1] * finalMatrix[1*4+2] +
- finalMatrix[3*4+2];
- b = finalMatrix[2*4+2];
- c = in[0] * finalMatrix[0*4+3] +
- in[1] * finalMatrix[1*4+3] +
- finalMatrix[3*4+3];
- d = finalMatrix[2*4+3];
-
- /*
- ** Ok, now we need to solve for z:
- ** (a + b z) / (c + d z) = height.
- ** ("height" is the height in object space we want to solve z for)
- **
- ** ==> a + b z = height c + height d z
- ** bz - height d z = height c - a
- ** z = (height c - a) / (b - height d)
- */
- top = height * c - a;
- bot = b - height * d;
- if (bot == 0.0) return 0;
-
- z = top / bot;
-
- /*
- ** Ok, no problem.
- ** Now we solve for x and y. We know that w = c + d z, so we compute it.
- */
- w = c + d * z;
-
- /*
- ** Now for x and y:
- */
- *selx = (in[0] * finalMatrix[0*4+0] +
- in[1] * finalMatrix[1*4+0] +
- z * finalMatrix[2*4+0] +
- finalMatrix[3*4+0]) / w - OFFSETX;
- *sely = (in[0] * finalMatrix[0*4+1] +
- in[1] * finalMatrix[1*4+1] +
- z * finalMatrix[2*4+1] +
- finalMatrix[3*4+1]) / w - OFFSETY;
- return 1;
- }
-
- static int selected;
- static int selectx, selecty;
- static float selstartx, selstarty;
-
- void grabPiece(int piece, float selx, float sely)
- {
- int hit;
-
- selectx=selx;
- selecty=sely;
- if (selectx < 0 || selecty < 0 || selectx >= WIDTH || selecty >= HEIGHT) {
- return;
- }
- hit = thePuzzle[selecty][selectx];
- if (hit != piece) return;
- if (hit) {
- movingPiece=hit;
- while (selectx > 0 && thePuzzle[selecty][selectx-1] == movingPiece) {
- selectx--;
- }
- while (selecty > 0 && thePuzzle[selecty-1][selectx] == movingPiece) {
- selecty--;
- }
- move_x=selectx;
- move_y=selecty;
- selected=1;
- selstartx=selx;
- selstarty=sely;
- } else {
- selected=0;
- }
- }
-
- void moveSelection(float selx, float sely)
- {
- float deltax, deltay;
- int dir;
- Config newpieces;
-
- if (!selected) return;
- deltax = selx - selstartx;
- deltay = sely - selstarty;
-
- if (fabs(deltax) > fabs(deltay)) {
- deltay = 0;
- if (deltax > 0) {
- if (deltax > 1) deltax = 1;
- dir = 2;
- } else {
- if (deltax < -1) deltax = -1;
- dir = 0;
- }
- } else {
- deltax = 0;
- if (deltay > 0) {
- if (deltay > 1) deltay = 1;
- dir = 3;
- } else {
- if (deltay < -1) deltay = -1;
- dir = 1;
- }
- }
- if (canmove(thePuzzle, selectx, selecty, dir, newpieces)) {
- move_x = deltax + selectx;
- move_y = deltay + selecty;
- if (deltax > 0.5) {
- memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
- selectx++;
- selstartx++;
- } else if (deltax < -0.5) {
- memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
- selectx--;
- selstartx--;
- } else if (deltay > 0.5) {
- memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
- selecty++;
- selstarty++;
- } else if (deltay < -0.5) {
- memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
- selecty--;
- selstarty--;
- }
- } else {
- if (deltay > 0 && thePuzzle[selecty][selectx] == 10 &&
- selectx == 1 && selecty == 3) {
- /* Allow visual movement of solution piece outside of the box */
- move_x = selectx;
- move_y = sely - selstarty + selecty;
- } else {
- move_x = selectx;
- move_y = selecty;
- }
- }
- }
-
- void dropSelection(void)
- {
- if (!selected) return;
- movingPiece = 0;
- selected = 0;
- }
-
- static int left_mouse, right_mouse;
- static int mousex, mousey;
- static int solving;
- static int spinning;
- static float lastquat[4];
- static int sel_piece;
-
- static void Reshape(int width, int height)
- {
-
- W = width;
- H = height;
- glViewport(0, 0, W, H);
- glGetIntegerv(GL_VIEWPORT, viewport);
- }
-
- static GLenum Key(int key, GLenum mask)
- {
- int piece;
- GLint x, y;
-
- if (!left_mouse && !right_mouse) {
- switch(key) {
- case TK_ESCAPE:
- tkQuit();
- case TK_d:
- case TK_D:
- if (solving) {
- freeSolutions();
- solving=0;
- movingPiece=0;
- }
- tkGetMouseLoc(&x, &y);
- piece = selectPiece(x, y);
- if (piece) {
- nukePiece(piece);
- }
- break;
- case TK_S:
- case TK_s:
- if (solving) {
- freeSolutions();
- solving=0;
- movingPiece=0;
- } else {
- printf("Solving...\n");
- if (solvePuzzle()) {
- solving = 1;
- }
- }
- break;
- case TK_R:
- case TK_r:
- if (solving) {
- freeSolutions();
- solving=0;
- movingPiece=0;
- }
- memcpy(thePuzzle, startConfig, HEIGHT*WIDTH);
- break;
- case TK_b:
- case TK_B:
- depth=1-depth;
- if (depth) {
- glEnable(GL_DEPTH_TEST);
- } else {
- glDisable(GL_DEPTH_TEST);
- }
- break;
- default:
- return GL_FALSE;
- }
- }
- return GL_TRUE;
- }
-
- static GLenum MouseUp(int mouseX, int mouseY, GLenum button)
- {
-
- if (button & TK_LEFTBUTTON) {
- left_mouse = GL_FALSE;
- dropSelection();
- return GL_TRUE;
- } else if (button & TK_RIGHTBUTTON) {
- right_mouse = GL_FALSE;
- return GL_TRUE;
- }
- return GL_FALSE;
- }
-
- static GLenum MouseDown(int mouseX, int mouseY, GLenum button)
- {
- int piece;
- float selx, sely;
-
- mousex = mouseX;
- mousey = mouseY;
- if (button & TK_LEFTBUTTON) {
- if (solving) {
- freeSolutions();
- solving=0;
- movingPiece=0;
- }
- left_mouse = GL_TRUE;
- sel_piece = selectPiece(mousex, mousey);
- if (computeCoords(sel_piece, mousex, mousey, &selx, &sely)) {
- grabPiece(sel_piece, selx, sely);
- }
- return GL_TRUE;
- } else if (button & TK_RIGHTBUTTON) {
- right_mouse = GL_TRUE;
- return GL_TRUE;
- }
- return GL_FALSE;
- }
-
- void animate(void)
- {
- int piece;
- float selx, sely;
- int x, y;
-
- if (right_mouse || left_mouse) {
- tkGetMouseLoc(&x, &y);
- if (right_mouse && !left_mouse) {
- if (mousex != x || mousey != y) {
- trackball(lastquat,
- 2.0*(W-mousex)/W - 1.0,
- 2.0*mousey/H - 1.0,
- 2.0*(W-x)/W - 1.0,
- 2.0*y/H - 1.0);
- spinning = 1;
- } else {
- spinning = 0;
- }
- } else {
- computeCoords(sel_piece, x, y, &selx, &sely);
- moveSelection(selx, sely);
- }
- mousex = x;
- mousey = y;
- }
- if (spinning) {
- add_quats(lastquat, curquat, curquat);
- }
- redraw();
- if (solving) {
- if (!continueSolving()) {
- solving = 0;
- }
- }
- }
-
- void init(void)
- {
- static float lmodel_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
- static float lmodel_twoside[] = { GL_FALSE };
- static float lmodel_local[] = { GL_FALSE };
- static float light0_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
- static float light0_diffuse[] = { 1.0, 1.0, 1.0, 0.0 };
- static float light0_position[] = { 0.8660254, 0.5, 1, 0 };
- static float light0_specular[] = { 0.0, 0.0, 0.0, 0.0 };
- static float bevel_mat_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
- static float bevel_mat_shininess[] = { 40.0 };
- static float bevel_mat_specular[] = { 0.0, 0.0, 0.0, 0.0 };
- static float bevel_mat_diffuse[] = { 1.0, 0.0, 0.0, 0.0 };
-
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- glEnable(GL_DEPTH_TEST);
- glClearDepth(1.0);
-
- glClearColor(0.5, 0.5, 0.5, 0.0);
- glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
- glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
- glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
- glEnable(GL_LIGHT0);
-
- glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local);
- glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
- glEnable(GL_LIGHTING);
-
- glMaterialfv(GL_FRONT, GL_AMBIENT, bevel_mat_ambient);
- glMaterialfv(GL_FRONT, GL_SHININESS, bevel_mat_shininess);
- glMaterialfv(GL_FRONT, GL_SPECULAR, bevel_mat_specular);
- glMaterialfv(GL_FRONT, GL_DIFFUSE, bevel_mat_diffuse);
-
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
- glShadeModel(GL_FLAT);
-
- trackball(curquat, 0.0, 0.0, 0.0, 0.0);
- srandom(time(NULL));
- }
-
- static void Usage(void)
- {
- printf("Usage: puzzle [-s]\n");
- printf(" -s: Run in single buffered mode\n");
- exit(-1);
- }
-
- void main(long argc, char** argv)
- {
- long i;
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
- case 's':
- doubleBuffer = 0;
- break;
- default:
- Usage();
- }
- } else {
- Usage();
- }
- }
-
-
- tkInitPosition(0, 0, W, H);
-
- tkInitDisplayMode(TK_DEPTH|TK_RGB|TK_DOUBLE|TK_DIRECT);
-
- if (tkInitWindow("Puzzle") == GL_FALSE) {
- tkQuit();
- }
-
- init();
-
- glGetIntegerv(GL_VIEWPORT, viewport);
-
- printf("\n\n\n\n\n\n");
- printf("r Reset puzzle\n");
- printf("s Solve puzzle (may take a few seconds to compute)\n");
- printf("d Destroy a piece - makes the puzzle easier\n");
- printf("b Toggles the depth buffer on and off\n");
- printf("\n");
- printf("Right mouse spins the puzzle\n");
- printf("Left mouse moves pieces\n");
-
-
- tkExposeFunc(Reshape);
- tkReshapeFunc(Reshape);
- tkKeyDownFunc(Key);
- tkMouseDownFunc(MouseDown);
- tkMouseUpFunc(MouseUp);
- tkIdleFunc(animate);
- tkExec();
- }
-